#ifndef ARMOR_DETECTOR__ARMOR_HPP_
#define ARMOR_DETECTOR__ARMOR_HPP_

#include <opencv2/core.hpp>

// STL
#include <algorithm>
#include <string>

namespace rm_aim
{
/**
 * @brief 装甲板/灯条颜色标识（宏定义）
 * @note RED=0 表示红色阵营，BLUE=1 表示蓝色阵营
 */
const int RED_CAMP = 0;    // 红色阵营标识
const int BLUE_CAMP = 1;   // 蓝色阵营标识

/**
 * @brief 装甲板类型枚举
 * @note 对应装甲板的物理尺寸分类，INVALID用于标记无效装甲板
 */
enum class ArmorType 
{ 
  SMALL,   // 小型装甲板
  LARGE,   // 大型装甲板
  INVALID  // 无效装甲板
};

/**
 * @brief 装甲板类型与字符串映射数组
 * @note 与ArmorType枚举顺序严格对应，用于日志打印或结果展示
 */
const std::string ARMOR_TYPE_STR[3] = {"small_armor", "large_armor", "invalid_armor"};

/**
 * @brief 灯条结构体（继承OpenCV旋转矩形，补充灯条关键参数）
 * @note 描述装甲板两侧发光灯条的几何特征与颜色信息
 */
struct Light : public cv::RotatedRect
{
  /**
   * @brief 默认构造函数
   */
  Light() = default;

  /**
   * @brief 从旋转矩形初始化灯条（核心构造逻辑）
   * @param rotated_rect 灯条的旋转矩形（包含位置、尺寸、旋转角度）
   * @note 自动计算灯条的上下顶点、长度、宽度、倾斜角度
   */
  explicit Light(cv::RotatedRect rotated_rect) : cv::RotatedRect(rotated_rect)
  {
    // 存储旋转矩形的四个顶点
    cv::Point2f rect_vertices[4];
    rotated_rect.points(rect_vertices);

    // 按y坐标排序顶点，获取灯条的上下两组顶点（y小的为上，y大的为下）
    std::sort(rect_vertices, rect_vertices + 4, 
              [](const cv::Point2f & a, const cv::Point2f & b) { return a.y < b.y; });
    
    // 计算灯条中心线上的上下顶点（上下两组顶点的中点）
    top_point = (rect_vertices[0] + rect_vertices[1]) / 2;  // 上顶点
    bottom_point = (rect_vertices[2] + rect_vertices[3]) / 2;  // 下顶点

    // 计算灯条长度（上下顶点间的距离，即灯条纵向尺寸）
    length_pixel = cv::norm(top_point - bottom_point);
    // 计算灯条宽度（上下两组顶点间的距离，即灯条横向尺寸）
    width_pixel = cv::norm(rect_vertices[0] - rect_vertices[1]);

    // 计算灯条倾斜角度（与竖直方向的夹角，单位：度）
    // 公式：arctan(水平偏移/垂直长度)，转换为角度便于理解
    tilt_angle_deg = std::atan2(std::abs(top_point.x - bottom_point.x), 
                                std::abs(top_point.y - bottom_point.y)) * 180 / CV_PI;
  }

  int camp_color;              // 灯条所属阵营颜色（取值：RED_CAMP=0 / BLUE_CAMP=1）
  cv::Point2f top_point;       // 灯条中心线上的上顶点（像素坐标）
  cv::Point2f bottom_point;    // 灯条中心线上的下顶点（像素坐标）
  double length_pixel;         // 灯条长度（像素单位，纵向尺寸）
  double width_pixel;          // 灯条宽度（像素单位，横向尺寸）
  float tilt_angle_deg;        // 灯条倾斜角度（与竖直方向的夹角，单位：度）
};

/**
 * @brief 装甲板结构体（描述单个装甲板的完整信息）
 * @note 包含灯条对、几何中心、类型，以及数字分类相关结果
 */
struct Armor
{
  /**
   * @brief 默认构造函数
   */
  Armor() = default;

  /**
   * @brief 从左右灯条初始化装甲板（核心构造逻辑）
   * @param left_light 左侧灯条（未排序前的灯条1）
   * @param right_light 右侧灯条（未排序前的灯条2）
   * @note 自动按x坐标排序灯条（x小的为左，x大的为右），计算装甲板中心
   */
  Armor(const Light & light_a, const Light & light_b)
  {
    // 按灯条中心x坐标排序，区分左右灯条（确保left_light在左侧）
    if (light_a.center.x < light_b.center.x) 
    {
      left_light = light_a;
      right_light = light_b;
    } 
    else 
    {
      left_light = light_b;
      right_light = light_a;
    }

    // 填充四个角点
    apex.emplace_back(left_light.top_point);
    apex.emplace_back(right_light.top_point);
    apex.emplace_back(right_light.bottom_point);
    apex.emplace_back(left_light.bottom_point);

    // 计算装甲板几何中心（左右灯条中心的中点）
    center_point = (left_light.center + right_light.center) / 2;
  }

  // -------------------------- 装甲板基础几何信息 --------------------------
  Light left_light;            // 装甲板左侧灯条（已按x坐标排序）
  Light right_light;           // 装甲板右侧灯条（已按x坐标排序）
  std::vector<cv::Point2f> apex;  // 装甲板四个角点（左上→右上→右下→左下）
  cv::Point2f center_point;    // 装甲板几何中心（像素坐标）
  ArmorType type;        // 装甲板类型（SMALL/LARGE/INVALID）

  // -------------------------- 数字分类相关信息 --------------------------
  cv::Mat number_roi_img;      // 装甲板上的数字ROI图像（二值化后，用于分类）
  std::string number;  // 分类得到的数字/标识（如"1"、"2"、"base"）
  float classification_conf;   // 数字分类置信度（0~1，值越高可信度越高）
  std::string classification_result;  // 分类结果字符串（含数字和置信度，用于日志）

  // -------------------------- 深度学习（端到端）模式相关信息 --------------------------
  float detect_conf;              // 装甲板整体检测置信度（0~1，区别于数字分类置信度，深度学习模式用）
  int area;                       // 装甲板面积（像素单位，两种模式均可填充）
};

}  // namespace rm_aim

#endif  // ARMOR_DETECTOR__ARMOR_HPP_